package com.xiaolei.fastnio.library.Adapters.Impls

import com.xiaolei.fastnio.library.Adapters.IClientAdapter
import com.xiaolei.fastnio.library.Client.Session
import com.xiaolei.fastnio.library.Protocol.IProtocol
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance

/**
 * 用自定义协议的客户端适配器，
 * 一个客户端一个解码器，直到客户端链接被断开，则回收解码器。
 * @param klass 自定义解码器
 */
abstract class ProtocolClientAdapter<T, R : IProtocol<T>>(private val klass: KClass<R>) : IClientAdapter
{
    /**
     * 空闲的解码器
     */
    private val ideStore = ConcurrentLinkedQueue<R>()

    /**
     * 正在使用的解码器
     */
    private val useStore = ConcurrentHashMap<Session, R>()


    override fun onOpen(session: Session)
    {
        var protocol = ideStore.poll()
        if (protocol == null)
        {
            protocol = klass.createInstance()
        }
        useStore[session] = protocol

        this.onSessionCreate(session)
    }

    override fun onReceive(session: Session, byteArray: ByteArray, len: Int)
    {
        var protocol = useStore[session]
        if (protocol == null)
        {
            protocol = ideStore.poll()
            if (protocol == null)
            {
                protocol = klass.createInstance()
            }
            useStore[session] = protocol
        }
        val data = protocol.decode(session, byteArray, len)
        if (data != null)
        {
            onSessionReceive(session, data)
        }
    }

    override fun onClose(session: Session)
    {
        val protocol = useStore.remove(session)
        if (protocol != null)
        {
            protocol.onClear()
            ideStore.offer(protocol)
        }
        this.onSessionClose(session)
    }

    /**
     * 打开会话
     */
    abstract fun onSessionCreate(session: Session)

    /**
     * 读取到数据
     */
    abstract fun onSessionReceive(session: Session, data: T)

    /**
     * 当会话关闭
     */
    abstract fun onSessionClose(session: Session)
}